#!/usr/bin/env python
# -*- coding: utf-8 -*-

import time
import uuid
import logging
from datetime import datetime, timedelta
from utility.tools import get_wechat_session_info
from authlib.jose import jwt
from config.settings import settings

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

_transient_max_hours = 7 * 24  # token失效时间

class WeChatAuthService:
    """
    微信认证服务
    提供微信登录和token校验功能
    """

    def __init__(self):
        self.cache_client = None  # Redis缓存客户端（包含MongoDB作为后备存储）

    def set_cache_client(self, cache_client):
        """设置缓存客户端（Redis+MongoDB）"""
        self.cache_client = cache_client

    def wechat_login(self, code):
        """
        微信登录认证
        @param code: 微信登录凭证code
        @param appid: 微信应用ID
        @param secret: 微信应用密钥
        @return: 登录结果和token信息
        """
        try:
            # 微信服务器验证code并返回用户信息
            if not code:
                return {
                    "code": 100,
                    "msg": "缺少登录凭证code"
                }

            # 微信验证过程
            if len(code) < 10:
                return {
                    "code": 100,
                    "msg": "无效的登录凭证"
                }

            # 通过code换取access_token和openid
            app_id, app_secret = settings.APP_ID, settings.APP_SECRET
            session_info = get_wechat_session_info(app_id, app_secret, code)
            if session_info.get('errcode'):
                return {'code': 102, 'msg': session_info.get('errmsg')}

            openid = session_info['openid']

            # 获取用户基本信息
            user_info = self._get_or_create_user(openid)

            # 生成token aud：user_id和exp：过期时间戳
            header = {'typ': 'JWT', 'alg': 'HS256'}  # 签名算法
            exp_date = datetime.now() + timedelta(seconds=_transient_max_hours * 3600)
            struct_time = exp_date.timetuple()  # struct_time类型
            exp = int(time.mktime(struct_time))
            payload = {'aud': user_info["user_id"], 'exp': exp}
            token = jwt.encode(header=header, payload=payload, key=settings.SECRET_KEY)  # byte类型
            token_str = token.decode('utf-8')

            # 保存token信息到缓存和数据库
            token_record = {
                "token": token_str,
                "openid": openid,
                "user_id": user_info["user_id"],
                "expires_at": datetime.strftime(exp_date, "%Y-%m-%d %H:%M:%S"),
                "created_at": datetime.strftime(datetime.now(), "%Y-%m-%d %H:%M:%S")
            }

            # 使用缓存客户端保存token（自动处理Redis和MongoDB）
            if self.cache_client:
                self.cache_client.save_token(token_str, token_record, _transient_max_hours * 3600)  # 7*24小时过期

            return {
                "code": 0,
                "data": {
                    "token": token_str,
                    "expires_in": _transient_max_hours * 3600,  # 7*24小时过期时间（秒）
                    "user_info": user_info
                }
            }

        except Exception as e:
            logger.error(f"微信登录失败: {e}")
            return {
                "code": 100,
                "msg": "登录过程出现错误"
            }

    def check_token(self, token):
        """
        校验微信token有效性
        @param token: 待校验的token
        @return: token校验结果和用户信息
        """
        try:
            if not token:
                return {
                    "code": 100,
                    "msg": "缺少token"
                }

            # 使用缓存客户端加载token（自动处理缓存和数据库）
            token_record = None
            if self.cache_client:
                token_record = self.cache_client.load_token(token)

            # 验证token有效性
            try:
                # 解码JWT token
                claims = jwt.decode(token, settings.SECRET_KEY)
                claims.validate()

                # 检查token是否在数据库中存在且未过期
                if token_record:
                    # 检查是否过期
                    if token_record.get("expires_at") and token_record["expires_at"] > datetime.now():
                        # 获取用户信息
                        user_info = self._get_user_info(claims.get("aud"))
                        return {
                            "code": 0,
                            "data": {
                                "user_info": user_info
                            }
                        }
                    else:
                        return {
                            "code": 100,
                            "msg": "token已过期"
                        }
                else:
                    return {
                        "code": 100,
                        "msg": "无效的token"
                    }
            except Exception as e:
                logger.error(f"Token解码失败: {e}")
                return {
                    "code": 100,
                    "msg": "token无效"
                }
        except Exception as e:
            logger.error(f"校验token失败: {e}")
            return {
                "code": 100,
                "msg": "token校验过程出现错误"
            }

    def logout(self, token):
        """
        登出操作，删除token
        @param token: 要删除的token
        @return: 操作结果
        """
        try:
            success = False
            if self.cache_client:
                success = self.cache_client.delete_token(token)

            if success:
                return {
                    "code": 0,
                    "msg": "登出成功"
                }
            else:
                return {
                    "code": 0,
                    "msg": "登出完成"
                }

        except Exception as e:
            logger.error(f"登出失败: {e}")
            return {
                "code": 100,
                "msg": "登出过程出现错误"
            }

    def _get_or_create_user(self, openid):
        """
        获取或创建用户信息
        @param openid: 微信用户唯一标识
        @return: 用户信息
        """
        user_info = None

        # 如果有缓存客户端，通过openid查找用户
        if self.cache_client:
            user_data = self.cache_client.find_user_by_openid(openid)
            if user_data and "profile" in user_data:
                user_info = user_data["profile"]

        # 如果用户不存在，则创建新用户
        if not user_info:
            user_info = {
                "user_id": str(uuid.uuid4()),
                "openid": openid,
                "nickname": f"用户_{openid[-6:]}",
                "avatar_url": "https://example.com/default_avatar.png",
                "created_at": datetime.strftime(datetime.now(), "%Y-%m-%d %H:%M:%S"),
                "last_login": datetime.strftime(datetime.now(), "%Y-%m-%d %H:%M:%S")
            }

            # 保存用户信息到数据库
            if self.cache_client:
                user_data = {
                    "x": 0,
                    "y": 0,
                    "inventory": [],
                    "profile": user_info
                }
                self.cache_client.save_user(user_info["user_id"], user_data, 3600)

        return user_info

    def _get_user_info(self, user_id):
        """
        根据用户ID获取用户信息
        @param user_id: 用户ID
        @return: 用户信息
        """
        if self.cache_client:
            user_data = self.cache_client.load_user(user_id)
            if user_data and "profile" in user_data:
                return user_data["profile"]

        # 如果数据库中没有找到，返回默认信息
        return {
            "user_id": user_id,
            "nickname": f"用户_{user_id[-6:]}",
            "avatar_url": "https://example.com/default_avatar.png"
        }


# 全局实例
wechat_auth_service = WeChatAuthService()
